home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / g_trigger.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  14.1 KB  |  599 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "g_local.h"
  21.  
  22.  
  23. void InitTrigger (edict_t *self)
  24. {
  25.     if (!VectorCompare (self->s.angles, vec3_origin))
  26.         G_SetMovedir (self->s.angles, self->movedir);
  27.  
  28.     self->solid = SOLID_TRIGGER;
  29.     self->movetype = MOVETYPE_NONE;
  30.     gi.setmodel (self, self->model);
  31.     self->svflags = SVF_NOCLIENT;
  32. }
  33.  
  34.  
  35. // the wait time has passed, so set back up for another activation
  36. void multi_wait (edict_t *ent)
  37. {
  38.     ent->nextthink = 0;
  39. }
  40.  
  41.  
  42. // the trigger was just activated
  43. // ent->activator should be set to the activator so it can be held through a delay
  44. // so wait for the delay time before firing
  45. void multi_trigger (edict_t *ent)
  46. {
  47.     if (ent->nextthink)
  48.         return;        // already been triggered
  49.  
  50.     G_UseTargets (ent, ent->activator);
  51.  
  52.     if (ent->wait > 0)    
  53.     {
  54.         ent->think = multi_wait;
  55.         ent->nextthink = level.time + ent->wait;
  56.     }
  57.     else
  58.     {    // we can't just remove (self) here, because this is a touch function
  59.         // called while looping through area links...
  60.         ent->touch = NULL;
  61.         ent->nextthink = level.time + FRAMETIME;
  62.         ent->think = G_FreeEdict;
  63.     }
  64. }
  65.  
  66. void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator)
  67. {
  68.     ent->activator = activator;
  69.     multi_trigger (ent);
  70. }
  71.  
  72. void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  73. {
  74.     if(other->client)
  75.     {
  76.         if (self->spawnflags & 2)
  77.             return;
  78.     }
  79.     else if (other->svflags & SVF_MONSTER)
  80.     {
  81.         if (!(self->spawnflags & 1))
  82.             return;
  83.     }
  84.     else
  85.         return;
  86.  
  87.     if (!VectorCompare(self->movedir, vec3_origin))
  88.     {
  89.         vec3_t    forward;
  90.  
  91.         AngleVectors(other->s.angles, forward, NULL, NULL);
  92.         if (_DotProduct(forward, self->movedir) < 0)
  93.             return;
  94.     }
  95.  
  96.     self->activator = other;
  97.     multi_trigger (self);
  98. }
  99.  
  100. /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
  101. Variable sized repeatable trigger.  Must be targeted at one or more entities.
  102. If "delay" is set, the trigger waits some time after activating before firing.
  103. "wait" : Seconds between triggerings. (.2 default)
  104. sounds
  105. 1)    secret
  106. 2)    beep beep
  107. 3)    large switch
  108. 4)
  109. set "message" to text string
  110. */
  111. void trigger_enable (edict_t *self, edict_t *other, edict_t *activator)
  112. {
  113.     self->solid = SOLID_TRIGGER;
  114.     self->use = Use_Multi;
  115.     gi.linkentity (self);
  116. }
  117.  
  118. void SP_trigger_multiple (edict_t *ent)
  119. {
  120.     if (ent->sounds == 1)
  121.         ent->noise_index = gi.soundindex ("misc/secret.wav");
  122.     else if (ent->sounds == 2)
  123.         ent->noise_index = gi.soundindex ("misc/talk.wav");
  124.     else if (ent->sounds == 3)
  125.         ent->noise_index = gi.soundindex ("misc/trigger1.wav");
  126.     
  127.     if (!ent->wait)
  128.         ent->wait = 0.2;
  129.     ent->touch = Touch_Multi;
  130.     ent->movetype = MOVETYPE_NONE;
  131.     ent->svflags |= SVF_NOCLIENT;
  132.  
  133.  
  134.     if (ent->spawnflags & 4)
  135.     {
  136.         ent->solid = SOLID_NOT;
  137.         ent->use = trigger_enable;
  138.     }
  139.     else
  140.     {
  141.         ent->solid = SOLID_TRIGGER;
  142.         ent->use = Use_Multi;
  143.     }
  144.  
  145.     if (!VectorCompare(ent->s.angles, vec3_origin))
  146.         G_SetMovedir (ent->s.angles, ent->movedir);
  147.  
  148.     gi.setmodel (ent, ent->model);
  149.     gi.linkentity (ent);
  150. }
  151.  
  152.  
  153. /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
  154. Triggers once, then removes itself.
  155. You must set the key "target" to the name of another object in the level that has a matching "targetname".
  156.  
  157. If TRIGGERED, this trigger must be triggered before it is live.
  158.  
  159. sounds
  160.  1)    secret
  161.  2)    beep beep
  162.  3)    large switch
  163.  4)
  164.  
  165. "message"    string to be displayed when triggered
  166. */
  167.  
  168. void SP_trigger_once(edict_t *ent)
  169. {
  170.     // make old maps work because I messed up on flag assignments here
  171.     // triggered was on bit 1 when it should have been on bit 4
  172.     if (ent->spawnflags & 1)
  173.     {
  174.         vec3_t    v;
  175.  
  176.         VectorMA (ent->mins, 0.5, ent->size, v);
  177.         ent->spawnflags &= ~1;
  178.         ent->spawnflags |= 4;
  179.         gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
  180.     }
  181.  
  182.     ent->wait = -1;
  183.     SP_trigger_multiple (ent);
  184. }
  185.  
  186. /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
  187. This fixed size trigger cannot be touched, it can only be fired by other events.
  188. */
  189. void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator)
  190. {
  191.     G_UseTargets (self, activator);
  192. }
  193.  
  194. void SP_trigger_relay (edict_t *self)
  195. {
  196.     self->use = trigger_relay_use;
  197. }
  198.  
  199.  
  200. /*
  201. ==============================================================================
  202.  
  203. trigger_key
  204.  
  205. ==============================================================================
  206. */
  207.  
  208. /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
  209. A relay trigger that only fires it's targets if player has the proper key.
  210. Use "item" to specify the required key, for example "key_data_cd"
  211. */
  212. void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
  213. {
  214.     int            index;
  215.  
  216.     if (!self->item)
  217.         return;
  218.     if (!activator->client)
  219.         return;
  220.  
  221.     index = ITEM_INDEX(self->item);
  222.     if (!activator->client->pers.inventory[index])
  223.     {
  224.         if (level.time < self->touch_debounce_time)
  225.             return;
  226.         self->touch_debounce_time = level.time + 5.0;
  227.         gi.centerprintf (activator, "You need the %s", self->item->pickup_name);
  228.         gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0);
  229.         return;
  230.     }
  231.  
  232.     gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0);
  233.     if (coop->value)
  234.     {
  235.         int        player;
  236.         edict_t    *ent;
  237.  
  238.         if (strcmp(self->item->classname, "key_power_cube") == 0)
  239.         {
  240.             int    cube;
  241.  
  242.             for (cube = 0; cube < 8; cube++)
  243.                 if (activator->client->pers.power_cubes & (1 << cube))
  244.                     break;
  245.             for (player = 1; player <= game.maxclients; player++)
  246.             {
  247.                 ent = &g_edicts[player];
  248.                 if (!ent->inuse)
  249.                     continue;
  250.                 if (!ent->client)
  251.                     continue;
  252.                 if (ent->client->pers.power_cubes & (1 << cube))
  253.                 {
  254.                     ent->client->pers.inventory[index]--;
  255.                     ent->client->pers.power_cubes &= ~(1 << cube);
  256.                 }
  257.             }
  258.         }
  259.         else
  260.         {
  261.             for (player = 1; player <= game.maxclients; player++)
  262.             {
  263.                 ent = &g_edicts[player];
  264.                 if (!ent->inuse)
  265.                     continue;
  266.                 if (!ent->client)
  267.                     continue;
  268.                 ent->client->pers.inventory[index] = 0;
  269.             }
  270.         }
  271.     }
  272.     else
  273.     {
  274.         activator->client->pers.inventory[index]--;
  275.     }
  276.  
  277.     G_UseTargets (self, activator);
  278.  
  279.     self->use = NULL;
  280. }
  281.  
  282. void SP_trigger_key (edict_t *self)
  283. {
  284.     if (!st.item)
  285.     {
  286.         gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
  287.         return;
  288.     }
  289.     self->item = FindItemByClassname (st.item);
  290.  
  291.     if (!self->item)
  292.     {
  293.         gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
  294.         return;
  295.     }
  296.  
  297.     if (!self->target)
  298.     {
  299.         gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
  300.         return;
  301.     }
  302.  
  303.     gi.soundindex ("misc/keytry.wav");
  304.     gi.soundindex ("misc/keyuse.wav");
  305.  
  306.     self->use = trigger_key_use;
  307. }
  308.  
  309.  
  310. /*
  311. ==============================================================================
  312.  
  313. trigger_counter
  314.  
  315. ==============================================================================
  316. */
  317.  
  318. /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
  319. Acts as an intermediary for an action that takes multiple inputs.
  320.  
  321. If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
  322.  
  323. After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
  324. */
  325.  
  326. void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
  327. {
  328.     if (self->count == 0)
  329.         return;
  330.     
  331.     self->count--;
  332.  
  333.     if (self->count)
  334.     {
  335.         if (! (self->spawnflags & 1))
  336.         {
  337.             gi.centerprintf(activator, "%i more to go...", self->count);
  338.             gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
  339.         }
  340.         return;
  341.     }
  342.     
  343.     if (! (self->spawnflags & 1))
  344.     {
  345.         gi.centerprintf(activator, "Sequence completed!");
  346.         gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
  347.     }
  348.     self->activator = activator;
  349.     multi_trigger (self);
  350. }
  351.  
  352. void SP_trigger_counter (edict_t *self)
  353. {
  354.     self->wait = -1;
  355.     if (!self->count)
  356.         self->count = 2;
  357.  
  358.     self->use = trigger_counter_use;
  359. }
  360.  
  361.  
  362. /*
  363. ==============================================================================
  364.  
  365. trigger_always
  366.  
  367. ==============================================================================
  368. */
  369.  
  370. /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
  371. This trigger will always fire.  It is activated by the world.
  372. */
  373. void SP_trigger_always (edict_t *ent)
  374. {
  375.     // we must have some delay to make sure our use targets are present
  376.     if (ent->delay < 0.2)
  377.         ent->delay = 0.2;
  378.     G_UseTargets(ent, ent);
  379. }
  380.  
  381.  
  382. /*
  383. ==============================================================================
  384.  
  385. trigger_push
  386.  
  387. ==============================================================================
  388. */
  389.  
  390. #define PUSH_ONCE        1
  391.  
  392. static int windsound;
  393.  
  394. void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  395. {
  396.     if (strcmp(other->classname, "grenade") == 0)
  397.     {
  398.         VectorScale (self->movedir, self->speed * 10, other->velocity);
  399.     }
  400.     else if (other->health > 0)
  401.     {
  402.         VectorScale (self->movedir, self->speed * 10, other->velocity);
  403.  
  404.         if (other->client)
  405.         {
  406.             // don't take falling damage immediately from this
  407.             VectorCopy (other->velocity, other->client->oldvelocity);
  408.             if (other->fly_sound_debounce_time < level.time)
  409.             {
  410.                 other->fly_sound_debounce_time = level.time + 1.5;
  411.                 gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
  412.             }
  413.         }
  414.     }
  415.     if (self->spawnflags & PUSH_ONCE)
  416.         G_FreeEdict (self);
  417. }
  418.  
  419.  
  420. /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
  421. Pushes the player
  422. "speed"        defaults to 1000
  423. */
  424. void SP_trigger_push (edict_t *self)
  425. {
  426.     InitTrigger (self);
  427.     windsound = gi.soundindex ("misc/windfly.wav");
  428.     self->touch = trigger_push_touch;
  429.     if (!self->speed)
  430.         self->speed = 1000;
  431.     gi.linkentity (self);
  432. }
  433.  
  434.  
  435. /*
  436. ==============================================================================
  437.  
  438. trigger_hurt
  439.  
  440. ==============================================================================
  441. */
  442.  
  443. /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
  444. Any entity that touches this will be hurt.
  445.  
  446. It does dmg points of damage each server frame
  447.  
  448. SILENT            supresses playing the sound
  449. SLOW            changes the damage rate to once per second
  450. NO_PROTECTION    *nothing* stops the damage
  451.  
  452. "dmg"            default 5 (whole numbers only)
  453.  
  454. */
  455. void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
  456. {
  457.     if (self->solid == SOLID_NOT)
  458.         self->solid = SOLID_TRIGGER;
  459.     else
  460.         self->solid = SOLID_NOT;
  461.     gi.linkentity (self);
  462.  
  463.     if (!(self->spawnflags & 2))
  464.         self->use = NULL;
  465. }
  466.  
  467.  
  468. void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  469. {
  470.     int        dflags;
  471.  
  472.     if (!other->takedamage)
  473.         return;
  474.  
  475.     if (self->timestamp > level.time)
  476.         return;
  477.  
  478.     if (self->spawnflags & 16)
  479.         self->timestamp = level.time + 1;
  480.     else
  481.         self->timestamp = level.time + FRAMETIME;
  482.  
  483.     if (!(self->spawnflags & 4))
  484.     {
  485.         if ((level.framenum % 10) == 0)
  486.             gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
  487.     }
  488.  
  489.     if (self->spawnflags & 8)
  490.         dflags = DAMAGE_NO_PROTECTION;
  491.     else
  492.         dflags = 0;
  493.     T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
  494. }
  495.  
  496. void SP_trigger_hurt (edict_t *self)
  497. {
  498.     InitTrigger (self);
  499.  
  500.     self->noise_index = gi.soundindex ("world/electro.wav");
  501.     self->touch = hurt_touch;
  502.  
  503.     if (!self->dmg)
  504.         self->dmg = 5;
  505.  
  506.     if (self->spawnflags & 1)
  507.         self->solid = SOLID_NOT;
  508.     else
  509.         self->solid = SOLID_TRIGGER;
  510.  
  511.     if (self->spawnflags & 2)
  512.         self->use = hurt_use;
  513.  
  514.     gi.linkentity (self);
  515. }
  516.  
  517.  
  518. /*
  519. ==============================================================================
  520.  
  521. trigger_gravity
  522.  
  523. ==============================================================================
  524. */
  525.  
  526. /*QUAKED trigger_gravity (.5 .5 .5) ?
  527. Changes the touching entites gravity to
  528. the value of "gravity".  1.0 is standard
  529. gravity for the level.
  530. */
  531.  
  532. void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  533. {
  534.     other->gravity = self->gravity;
  535. }
  536.  
  537. void SP_trigger_gravity (edict_t *self)
  538. {
  539.     if (st.gravity == 0)
  540.     {
  541.         gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
  542.         G_FreeEdict  (self);
  543.         return;
  544.     }
  545.  
  546.     InitTrigger (self);
  547.     self->gravity = atoi(st.gravity);
  548.     self->touch = trigger_gravity_touch;
  549. }
  550.  
  551.  
  552. /*
  553. ==============================================================================
  554.  
  555. trigger_monsterjump
  556.  
  557. ==============================================================================
  558. */
  559.  
  560. /*QUAKED trigger_monsterjump (.5 .5 .5) ?
  561. Walking monsters that touch this will jump in the direction of the trigger's angle
  562. "speed" default to 200, the speed thrown forward
  563. "height" default to 200, the speed thrown upwards
  564. */
  565.  
  566. void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  567. {
  568.     if (other->flags & (FL_FLY | FL_SWIM) )
  569.         return;
  570.     if (other->svflags & SVF_DEADMONSTER)
  571.         return;
  572.     if ( !(other->svflags & SVF_MONSTER))
  573.         return;
  574.  
  575. // set XY even if not on ground, so the jump will clear lips
  576.     other->velocity[0] = self->movedir[0] * self->speed;
  577.     other->velocity[1] = self->movedir[1] * self->speed;
  578.     
  579.     if (!other->groundentity)
  580.         return;
  581.     
  582.     other->groundentity = NULL;
  583.     other->velocity[2] = self->movedir[2];
  584. }
  585.  
  586. void SP_trigger_monsterjump (edict_t *self)
  587. {
  588.     if (!self->speed)
  589.         self->speed = 200;
  590.     if (!st.height)
  591.         st.height = 200;
  592.     if (self->s.angles[YAW] == 0)
  593.         self->s.angles[YAW] = 360;
  594.     InitTrigger (self);
  595.     self->touch = trigger_monsterjump_touch;
  596.     self->movedir[2] = st.height;
  597. }
  598.  
  599.